﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using System.Diagnostics;
using PuzzleDeluxe.bamboo;
using JumpyCat.bamboo;

namespace PuzzleDulex.bamboo
{
    public class Board
    {
        public const int BOARD_WIDTH = 480;
        public const int BOARD_HEIGHT = 480;
        public const int BOARD_MARGIN_LEFT = 5;
        public const int BOARD_MARGIN_TOP = 310;
        public const int PADDING = 5;
        public const int SPEED_MOVING_SQUARE = 6;

        public Rect boardRect;
        public PuzzleState endState;

        public Score currentHightScore = null;

        public MyTimer timer = new MyTimer();


        /// <summary>
        /// Use for determine move square direction
        /// </summary>
        public bool isMovingSquare = false;
        public bool isFinished = false;

        public enum DIRECTION_MOVE { UP, LEFT, RIGHT, DOWN, NONE };
        public DIRECTION_MOVE dir = DIRECTION_MOVE.NONE;

        public int numberStep = 0;
        public int currentImageIndex = 0;

        Square currentSpaceSquare;
        Square touchSwapeSquare;

        // Graphic
        public Texture2D picture;
        private Square[] listSquare;

        public Board(TILE[] startState)
        {
            boardRect = new Rect(Board.BOARD_MARGIN_LEFT, Board.BOARD_MARGIN_TOP, Board.BOARD_WIDTH, Board.BOARD_HEIGHT);
            listSquare = new Square[PuzzleState.BOARD_WIDTH * PuzzleState.BOARD_HEIGHT];
            this.setListSquare(startState);

            currentHightScore = SaveHighScoreHelper.getHighScore();
        }


        public Score getGameOverScore()
        {
            return new Score((long)this.timer.timePass, this.numberStep);
        }

        public int getRandomImageIndex()
        {
            Random randGenarator = new Random();
            int randIndex = randGenarator.Next(10);
            return randIndex;

        }

        public void Init(ContentManager Content)
        {
            int randIndex = this.getRandomImageIndex();
            randIndex += 1;
            picture = Content.Load<Texture2D>("picture" + randIndex);
            timer.resetTimer();
            timer.start = true;
        }

        public void setListSquare(TILE[] listSqr)
        {
            for (int i = 0; i < PuzzleState.BOARD_WIDTH * PuzzleState.BOARD_HEIGHT; i++)
            {
                listSquare[i] = new Square(listSqr[i], i);
            }

        }


        public Square GetSpaceTile(Square[] listSqr)
        {
            for (int i = 0; i < PuzzleState.BOARD_WIDTH * PuzzleState.BOARD_HEIGHT; i++)
            {

                if (listSqr[i].tile == TILE.TL_SPACE)
                {
                    return listSqr[i];
                }
            }

            return null;
        }

        public Square GetSquareByIndexInBoard(int index)
        {
            for (int i = 0; i < PuzzleState.BOARD_WIDTH * PuzzleState.BOARD_HEIGHT; i++)
            {

                if (listSquare[i].index == index)
                {
                    return listSquare[i];
                }
            }

            return null;

        }

        public bool IsGoal()
        {
            return IsSameState(endState);
        }

        public bool IsSameState(PuzzleState rhs)
        {
            for (int i = 0; i < (PuzzleState.BOARD_HEIGHT * PuzzleState.BOARD_WIDTH); i++)
            {
                Square temp = this.GetSquareByIndexInBoard(i);

                if (temp.tile != rhs.tiles[i])
                {
                    return false;
                }
            }

            return true;

        }

        public Square getSquareBeTouched(int x, int y)
        {
            Square touchedSquare = null;

            for (int i = 0; i < listSquare.Length; i++)
            {
                Square currentSquare = listSquare[i];
                if (currentSquare.isTouchInside(x, y))
                {
                    touchedSquare = currentSquare;
                    break;
                }
            }

            return touchedSquare;

        }

        public void handleTouchIn(int x, int y)
        {
            if (isMovingSquare)
            {
                return;
            }

            bool isTouchInBoard = boardRect.isPointInRect(x, y);
            dir = DIRECTION_MOVE.NONE;

            if (isTouchInBoard)
            {
                touchSwapeSquare = this.getSquareBeTouched(x, y);
                currentSpaceSquare = this.GetSpaceTile(this.listSquare);


                if (touchSwapeSquare == null)
                {
                    return;
                }
                else
                {
                    bool squareNearSpaceSquare = touchSwapeSquare.isNearSquare(currentSpaceSquare);

                    if (!squareNearSpaceSquare)
                    {
                        return;
                    }
                    else
                    {

                        this.getMoveDirection();
                        Debug.WriteLine("Touch in a square near space Tile, go to " + dir.ToString());


                    }

                }

            }
        }

        void getMoveDirection()
        {
            SimpleSoundManager.PlayTouchTileSound();
            
            if (touchSwapeSquare.X == currentSpaceSquare.X)
            {
                if (touchSwapeSquare.Y > currentSpaceSquare.Y)
                {
                    dir = DIRECTION_MOVE.UP;

                }
                else
                {
                    dir = DIRECTION_MOVE.DOWN;
                }
            }
            else
            {
                if (touchSwapeSquare.X > currentSpaceSquare.X)
                {
                    dir = DIRECTION_MOVE.LEFT;

                }
                else
                {
                    dir = DIRECTION_MOVE.RIGHT;
                }

            }
        }

        void animateTranferToNextState()
        {
            isMovingSquare = true;

            switch (dir)
            {
                case DIRECTION_MOVE.UP:

                    touchSwapeSquare.rectToDraw.Y -= SPEED_MOVING_SQUARE;

                    if (touchSwapeSquare.rectToDraw.Y <= currentSpaceSquare.rectToDraw.Y)
                    {
                        touchSwapeSquare.rectToDraw.Y = currentSpaceSquare.rectToDraw.Y;
                        isMovingSquare = false;
                    }

                    break;

                case DIRECTION_MOVE.DOWN:
                    touchSwapeSquare.rectToDraw.Y += SPEED_MOVING_SQUARE;
                    if (touchSwapeSquare.rectToDraw.Y >= currentSpaceSquare.rectToDraw.Y)
                    {
                        touchSwapeSquare.rectToDraw.Y = currentSpaceSquare.rectToDraw.Y;
                        isMovingSquare = false;
                    }

                    break;

                case DIRECTION_MOVE.LEFT:
                    touchSwapeSquare.rectToDraw.X -= SPEED_MOVING_SQUARE;
                    if (touchSwapeSquare.rectToDraw.X <= currentSpaceSquare.rectToDraw.X)
                    {
                        isMovingSquare = false;
                        touchSwapeSquare.rectToDraw.X = currentSpaceSquare.rectToDraw.X;
                    }

                    break;

                case DIRECTION_MOVE.RIGHT:
                    touchSwapeSquare.rectToDraw.X += SPEED_MOVING_SQUARE;
                    if (touchSwapeSquare.rectToDraw.X >= currentSpaceSquare.rectToDraw.X)
                    {
                        isMovingSquare = false;
                        touchSwapeSquare.rectToDraw.X = currentSpaceSquare.rectToDraw.X;
                    }
                    break;

            }




            if (!isMovingSquare)
            {
                dir = DIRECTION_MOVE.NONE;
                int spaceIndex = currentSpaceSquare.index;
                currentSpaceSquare.index = touchSwapeSquare.index;
                touchSwapeSquare.index = spaceIndex;

                currentSpaceSquare.resetAttributes();
                touchSwapeSquare.resetAttributes();
                numberStep ++;

                isFinished = this.IsGoal();
                if (isFinished)
                {
                    SimpleSoundManager.PlayFinishGameSound();
                    timer.pauseTimer();
                }
            }

        }



        int getIndexOfSpaceTile(TILE[] tiles)
        {
            for (int i = 0; i < PuzzleState.BOARD_HEIGHT * PuzzleState.BOARD_WIDTH; i++)
            {
                if (tiles[i] == TILE.TL_SPACE)
                {
                    return i;
                }
            }
            return (-1);
        }

        void randomSwapTile(TILE[] tiles)
        {
            List<int> indexSwaps = new List<int>();
            int indexSpaceTile = getIndexOfSpaceTile(tiles);
            switch (indexSpaceTile)
            {
                case 0:
                    indexSwaps.Add(1);
                    indexSwaps.Add(3);
                    break;
                case 1:
                    indexSwaps.Add(0);
                    indexSwaps.Add(2);
                    indexSwaps.Add(4);
                    break;
                case 2:
                    indexSwaps.Add(1);
                    indexSwaps.Add(5);
                    break;
                case 3:
                    indexSwaps.Add(0);
                    indexSwaps.Add(4);
                    indexSwaps.Add(6);
                    break;

                case 4:
                    indexSwaps.Add(1);
                    indexSwaps.Add(3);
                    indexSwaps.Add(5);
                    indexSwaps.Add(7);
                    break;
                case 5:
                    indexSwaps.Add(2);
                    indexSwaps.Add(4);
                    indexSwaps.Add(8);

                    break;
                case 6:
                    indexSwaps.Add(3);
                    indexSwaps.Add(7);
                    break;
                case 7:
                    indexSwaps.Add(6);
                    indexSwaps.Add(4);
                    indexSwaps.Add(8);
                    break;
                case 8:
                    indexSwaps.Add(5);
                    indexSwaps.Add(7);
                    break;

            }

            Random rand = new Random();
            int randIndex = rand.Next(0, indexSwaps.Count);
            int swapTileIndex = indexSwaps[randIndex];
            TILE temp;
            temp = tiles[swapTileIndex];
            tiles[indexSpaceTile] = temp;
            tiles[swapTileIndex] = TILE.TL_SPACE;

        }

        TILE[] getShuffleTile()
        {
            Random rand = new Random();
            TILE[] randTile = new TILE[PuzzleState.BOARD_HEIGHT * PuzzleState.BOARD_WIDTH];
            for (int i = 0; i < PuzzleState.BOARD_HEIGHT * PuzzleState.BOARD_WIDTH; i++)
            {
                randTile[i] = Game1.nodeEnd.tiles[i];
            }

            //int timeShuffle = rand.Next(300, 600);
            int timeShuffle = 1;
            int count = 0;
            while (count < timeShuffle)
            {
                randomSwapTile(randTile);
                count++;
            }

            return randTile;
        }


        /// <summary>
        /// Function to random image and shuffle position of tiles
        /// </summary>
        /// <param name="gameTime"></param>
        /// 

        public void RandomAndShuffleTile(ContentManager content)
        {

            Game1.nodeStart = new PuzzleState(this.getShuffleTile());
            Game1.nodeEnd = new PuzzleState(PuzzleState.g_goal);

            Game1.gameBoard = new Board(Game1.nodeStart.tiles);
            Game1.gameBoard.Init(content);
            Game1.preview = new PreviewArea(Game1.gameBoard.picture);
            Game1.gameBoard.endState = Game1.nodeEnd;
            
            isMovingSquare = false;
            isFinished = false;
        }

        public void Update(GameTime gameTime)
        {
            if (dir != DIRECTION_MOVE.NONE)
            {
                animateTranferToNextState();
            }
        }

        /// <summary>
        /// Draw board game here
        /// </summary>
        /// <param name="g"></param>

        private void DrawTiles(SpriteBatch g)
        {
            for (int i = 0; i < PuzzleState.BOARD_WIDTH * PuzzleState.BOARD_HEIGHT; i++)
            {
                if (listSquare[i].tile != TILE.TL_SPACE)
                {
                    g.Draw(picture, listSquare[i].rectToDraw, listSquare[i].rectSourceToDraw, Color.White);

                }
            }

        }

        private void DrawTimerAndStep(SpriteBatch g)
        {
            TextUtil.printString(g, 280, 200, "Step: " + numberStep.ToString(), 0, Color.Purple);
        }

        public void DrawNumberStep(SpriteBatch g, int x, int y, Color color)
        {
            TextUtil.printString(g, x, y, "Step: " + numberStep.ToString(), 0, color);
        }

        public void Draw(SpriteBatch g)
        {
            this.DrawTiles(g);
            DrawTimerAndStep(g);
            if (isFinished)
            {
                DrawSpaceTile(g);
            }
            
        }

        public void DrawSpaceTile(SpriteBatch g)
        {
            currentSpaceSquare = this.GetSpaceTile(listSquare);
            g.Draw(picture, currentSpaceSquare.rectToDraw, currentSpaceSquare.rectSourceToDraw, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 1.0f);
        }

    }
}
